home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / pgp23src.zip / FILEIO.C < prev    next >
C/C++ Source or Header  |  1993-05-09  |  27KB  |  1,087 lines

  1. /*    fileio.c  - I/O routines for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19.  
  20.     Modified 16 Apr 92 - HAJK
  21.     Mods for support of VAX/VMS file system
  22.  
  23.     Modified 17 Nov 92 - HAJK
  24.     Change to temp file stuff for VMS.
  25. */
  26.  
  27. #include <ctype.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <errno.h>
  32. #ifdef UNIX
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #ifdef _BSD
  37. #include <sys/param.h>
  38. #endif
  39. extern int errno;
  40. #endif /* UNIX */
  41. #ifdef VMS
  42. #include <file.h>
  43. #endif
  44. #include "random.h"
  45. #include "mpilib.h"
  46. #include "mpiio.h"
  47. #include "fileio.h"
  48. #include "language.h"
  49. #include "pgp.h"
  50. #include "exitpgp.h"
  51. #include "charset.h"
  52. #include "system.h"
  53. #if defined(MSDOS) || defined(OS2)
  54. #include <io.h>
  55. #include <fcntl.h>
  56. #endif
  57.  
  58. #if (defined(VMS) || defined(UNIX)) && !defined(F_OK)
  59. #define F_OK    0
  60. #define X_OK    1
  61. #define W_OK    2
  62. #define R_OK    4
  63. #endif /* !F_OK */
  64.  
  65. /* 1st character of temporary file extension */
  66. #define    TMP_EXT    '$'        /* extensions are '.$##' */
  67.  
  68. /* The PGPPATH environment variable */
  69.  
  70. static char PGPPATH[] = "PGPPATH";
  71.  
  72. /* Disk buffers, used here and in crypto.c */
  73. byte textbuf[DISKBUFSIZE];
  74. static byte textbuf2[2*DISKBUFSIZE];
  75.  
  76. boolean file_exists(char *filename)
  77. /*    Returns TRUE iff file exists. */
  78. {
  79. #if defined(UNIX) || defined(VMS)
  80.     return(access(filename, F_OK) == 0);
  81. #else
  82.     FILE *f;
  83.     /* open file f for read, in binary (not text) mode...*/
  84.     if ((f = fopen(filename,FOPRBIN)) == NULL)
  85.         return(FALSE);
  86.     fclose(f);
  87.     return(TRUE);
  88. #endif
  89. }    /* file_exists */
  90.  
  91. static boolean is_regular_file(char *filename)
  92. {
  93. #ifdef S_ISREG
  94.     struct stat st;
  95.     return(stat(filename, &st) != -1 && S_ISREG(st.st_mode));
  96. #else
  97.     return TRUE;
  98. #endif
  99. }
  100.  
  101. static int wipeout(FILE *f)
  102. {    /*    Completely overwrite and erase file, so that no sensitive
  103.         information is left on the disk.
  104.         NOTE:  File MUST be open for read/write.
  105.     */
  106.  
  107.     long flength;
  108.     int count = 0;
  109.  
  110.     fseek(f, 0L, SEEK_END);
  111.     flength = ftell(f);
  112.     rewind(f);
  113.  
  114.     fill0(textbuf, sizeof(textbuf));
  115.     while (flength > 0L)
  116.     {    /* write zeros to the whole file... */
  117.         if (flength < (word32) DISKBUFSIZE)
  118.             count = (int)flength;
  119.         else
  120.             count = DISKBUFSIZE;
  121.         fwrite(textbuf,1,count,f);
  122.         flength -= count;
  123.     }
  124.     rewind(f);    /* maybe this isn't necessary */
  125.     return(0);    /* normal return */
  126. }    /* wipeout */
  127.  
  128.  
  129. int wipefile(char *filename)
  130. {    /*    Completely overwrite and erase file, so that no sensitive
  131.         information is left on the disk.
  132.     */
  133.     FILE *f;
  134.     /* open file f for read/write, in binary (not text) mode...*/
  135.     if ((f = fopen(filename,FOPRWBIN)) == NULL)
  136.         return(-1);    /* error - file can't be opened */
  137.     wipeout(f);
  138.     fclose(f);
  139.     return(0);    /* normal return */
  140. }    /* wipefile */
  141.  
  142. char    *file_tail (char *filename)
  143. /*    Returns the after-slash part of filename.  Also skips backslashes,
  144.  *  colons, and right brackets.    */
  145. {
  146.     char *bslashPos = strrchr(filename, '\\');/* Find last bslash in filename */
  147.     char *slashPos = strrchr(filename, '/');/* Find last slash in filename */
  148.     char *colonPos = strrchr(filename, ':');
  149.     char *rbrakPos = strrchr(filename, ']');
  150.  
  151.     if (!slashPos  ||  bslashPos > slashPos)
  152.         slashPos = bslashPos;
  153.     if (!slashPos  ||  colonPos > slashPos)
  154.         slashPos = colonPos;
  155.     if (!slashPos  ||  rbrakPos > slashPos)
  156.         slashPos = rbrakPos;
  157.     return( slashPos?(slashPos+1):filename );
  158. }
  159. /* Define BSLASH for machines that use backslash, FSLASH for machines
  160.  * that use forward slash as separators.
  161.  */
  162.  
  163. #ifdef MSDOS
  164. #define    BSLASH
  165. #endif
  166. #ifdef ATARI
  167. #define BSLASH
  168. #endif
  169. #ifdef UNIX
  170. #define FSLASH
  171. #define MULTIPLE_DOTS
  172. #endif
  173. #ifdef AMIGA
  174. #define FSLASH
  175. #define MULTIPLE_DOTS
  176. #endif
  177.  
  178. boolean has_extension(char *filename, char *extension)
  179. {    /* return TRUE if extension matches the end of filename */
  180.     int lf = strlen(filename);
  181.     int lx = strlen(extension);
  182.  
  183.     if (lf <= lx)
  184.         return(FALSE);
  185.     return(!strcmp(filename + lf - lx, extension));
  186. }
  187.  
  188. boolean is_tempfile(char *path)
  189. {    /* return TRUE if path is a filename created by tempfile() */
  190.     char *p;
  191.     
  192.     return((p = strrchr(path, '.')) != NULL &&
  193.             p[1] == TMP_EXT && strlen(p) == 4);
  194. }
  195.  
  196. boolean no_extension(char *filename)
  197. /*    Returns TRUE if user left off file extension, allowing default. */
  198. {
  199. #ifdef MULTIPLE_DOTS    /* filename can have more than one dot */
  200.     if (has_extension(filename, ASC_EXTENSION) ||
  201.         has_extension(filename, PGP_EXTENSION) ||
  202.         has_extension(filename, SIG_EXTENSION) ||
  203.         is_tempfile(filename))
  204.         return(FALSE);
  205.     else
  206.         return(TRUE);
  207. #else
  208. #ifdef BSLASH
  209.     char *slashPos = strrchr(filename, '\\');    /* Find last slash in filename */
  210.  
  211.     /* Look for the filename after the last slash if there is one */
  212.     return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL);
  213. #else
  214. #ifdef FSLASH
  215.     char *slashPos = strrchr(filename, '/');    /* Find last slash in filename */
  216.  
  217.     /* Look for the filename after the last slash if there is one */
  218.     return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL);
  219. #else
  220. #ifdef VMS
  221.     char *slashPos = strrchr(filename,']');        /* Locate end of directory spec */
  222.  
  223.     /* Look for last period in filename */
  224.     return(strrchr((slashPos != NULL) ? slashPos : filename, '.') == NULL );
  225. #else
  226.     return( (strrchr(filename,'.')==NULL) ? TRUE : FALSE );
  227. #endif /* VMS */
  228. #endif /* FSLASH */
  229. #endif /* BSLASH */
  230. #endif /* MULTIPLE_DOTS */
  231. }    /* no_extension */
  232.  
  233.  
  234. void drop_extension(char *filename)
  235. {    /* deletes trailing ".xxx" file extension after the period. */
  236.     if (!no_extension(filename))
  237.         *strrchr(filename,'.') = '\0';
  238. }    /* drop_extension */
  239.  
  240.  
  241. void default_extension(char *filename, char *extension)
  242. {    /* append filename extension if there isn't one already. */
  243.     if (no_extension(filename))
  244.         strcat(filename,extension);
  245. }    /* default_extension */
  246.  
  247. #ifndef MAX_NAMELEN
  248. #if defined(AMIGA) || defined(NeXT) || (defined(BSD) && BSD > 41)
  249. #define    MAX_NAMELEN    255
  250. #else
  251. #include <limits.h>
  252. #endif
  253. #endif
  254.  
  255. static void truncate_name(char *path, int ext_len)
  256. {    /* truncate the filename so that an extension can be tacked on. */
  257. #ifdef UNIX        /* for other systems this is a no-op */
  258.     char *p;
  259. #ifdef MAX_NAMELEN    /* overrides the use of pathconf() */
  260.     int namemax = MAX_NAMELEN;
  261. #else
  262.     int namemax;
  263. #ifdef _PC_NAME_MAX
  264.     char dir[MAX_PATH];
  265.  
  266.     strcpy(dir, path);
  267.     if ((p = strrchr(dir, '/')) == NULL)
  268.         strcpy(dir, ".");
  269.     else
  270.     {    if (p == dir)
  271.             ++p;
  272.         *p = '\0';
  273.     }
  274.     if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len)
  275.         return;
  276. #else
  277. #ifdef NAME_MAX
  278.     namemax = NAME_MAX;
  279. #else
  280.     namemax = 14;
  281. #endif /* NAME_MAX */
  282. #endif /* _PC_NAME_MAX */
  283. #endif /* MAX_NAMELEN */
  284.  
  285.     if ((p = strrchr(path, '/')) == NULL)
  286.         p = path;
  287.     else
  288.         ++p;
  289.     if (strlen(p) > namemax - ext_len)
  290.     {
  291.         if (verbose)
  292.             fprintf(pgpout, "Truncating filename '%s' ", path);
  293.         p[namemax - ext_len] = '\0';
  294.         if (verbose)
  295.             fprintf(pgpout, "to '%s'\n", path);
  296.     }
  297. #endif /* UNIX */
  298. }
  299.  
  300. void force_extension(char *filename, char *extension)
  301. {    /* change the filename extension. */
  302.     drop_extension(filename);    /* out with the old */
  303.     truncate_name(filename, strlen(extension));
  304.     strcat(filename,extension);    /* in with the new */
  305. }    /* force_extension */
  306.  
  307.  
  308. boolean getyesno(char default_answer)
  309. /*    Get yes/no answer from user, returns TRUE for yes, FALSE for no. 
  310.     First the translations are checked, if they don't match 'y' and 'n'
  311.     are tried.
  312. */
  313. {    char buf[8];
  314.     static char yes[8], no[8];
  315.  
  316.     if (yes[0] == '\0')
  317.     {    strncpy(yes, PSTR("y"), 7);
  318.         strncpy(no, PSTR("n"), 7);
  319.     }
  320.     if (!batchmode) /* return default answer in batchmode */
  321.     {    flush_input();
  322.         getstring(buf,6,TRUE);    /* echo keyboard input */
  323.         strlwr(buf);
  324.         if (!strncmp(buf, no, strlen(no)))
  325.             return(FALSE);
  326.         if (!strncmp(buf, yes, strlen(yes)))
  327.             return(TRUE);
  328.         if (buf[0] == 'n')
  329.             return(FALSE);
  330.         if (buf[0] == 'y')
  331.             return(TRUE);
  332.     }
  333.     return(default_answer == 'y' ? TRUE : FALSE);
  334. }    /* getyesno */
  335.  
  336.  
  337.  
  338. char *maybe_force_extension(char *filename, char *extension)
  339. {    /* if user consents to it, change the filename extension. */
  340.     static char newname[MAX_PATH];
  341.     if (!has_extension(filename,extension))
  342.     {    strcpy(newname,filename);
  343.         force_extension(newname,extension);
  344.         if (!file_exists(newname))
  345.         {    fprintf(pgpout,PSTR("\nShould '%s' be renamed to '%s' [Y/n]? "),
  346.                 filename,newname);
  347.             if (getyesno('y'))
  348.                 return(newname);
  349.         }
  350.     }
  351.     return(NULL);
  352. }    /* maybe_force_extension */
  353.  
  354. char *buildfilename(char *result, char *fname)
  355. /*    Builds a filename with a complete path specifier from the environmental
  356.     variable PGPPATH.
  357. */
  358. {    char *s = getenv(PGPPATH);
  359.  
  360.     if ( s==NULL || strlen(s) > 50) /* undefined, or too long to use */
  361.         s="";
  362.     strcpy(result,s);
  363.     if (strlen(result) != 0)
  364. #ifdef BSLASH
  365.         if (result[strlen(result)-1] != '\\')
  366.             strcat(result,"\\");
  367. #else
  368. #ifdef FSLASH
  369.         if (result[strlen(result)-1] != '/')
  370.             strcat(result,"/");
  371. #else
  372. #ifdef VMS
  373.         if (result[strlen(result)-1] != ']')
  374.             strcat(result,"]");
  375. #endif
  376. #endif
  377. #endif /* Various OS-specific defines */
  378.     strcat(result,fname);
  379.     return(result);
  380. }    /* buildfilename */
  381.  
  382.  
  383. void file_to_canon(char *filename)
  384. {    /* Convert filename to canonical form, with slashes as separators */
  385. #ifdef BSLASH
  386.     while (*filename) {
  387.         if (*filename == '\\')
  388.             *filename = '/';
  389.         ++filename;
  390.     }
  391. #endif
  392. }
  393.  
  394.  
  395. int write_error(FILE *f)
  396. {
  397.     fflush(f);
  398.     if (ferror(f))
  399.     {
  400. #ifdef ENOSPC
  401.         if (errno == ENOSPC)
  402.             fprintf(pgpout, PSTR("\nDisk full.\n"));
  403.         else
  404. #endif
  405.             fprintf(pgpout, PSTR("\nFile write error.\n"));
  406.         return -1;
  407.     }
  408.     return 0;
  409. }
  410.  
  411. int copyfile(FILE *f, FILE *g, word32 longcount)
  412. {    /* copy file f to file g, for longcount bytes */
  413.     int count, status = 0;
  414.     do    /* read and write the whole file... */
  415.     {
  416.         if (longcount < (word32) DISKBUFSIZE)
  417.             count = (int)longcount;
  418.         else
  419.             count = DISKBUFSIZE;
  420.         count = fread(textbuf,1,count,f);
  421.         if (count>0)
  422.         {
  423.             if (CONVERSION != NO_CONV)
  424.             {       int i;
  425.                 for (i = 0; i < count; i++)
  426.                     textbuf[i] = (CONVERSION == EXT_CONV) ?
  427.                              EXT_C(textbuf[i]) :
  428.                              INT_C(textbuf[i]);
  429.             }
  430.             if (fwrite(textbuf,1,count,g) != count )
  431.             {   /* Problem: return error value */
  432.                 status = -1;
  433.                 break;
  434.             }
  435.             longcount -= count;
  436.         }
  437.         /* if text block was short, exit loop */
  438.     } while (count==DISKBUFSIZE);
  439.     burn(textbuf);    /* burn sensitive data on stack */
  440.     return(status);
  441. }    /* copyfile */
  442.  
  443. int copyfilepos (FILE *f, FILE *g, word32 longcount, word32 fpos)
  444. /* Like copyfile, but takes a position for file f.  Returns with
  445.  * f and g pointing just past the copied data.
  446.  */
  447. {
  448.     fseek (f, fpos, SEEK_SET);
  449.     return copyfile (f, g, longcount);
  450. }
  451.  
  452.  
  453. int copyfile_to_canon (FILE *f, FILE *g, word32 longcount)
  454. {    /* copy file f to file g, for longcount bytes.  Convert to
  455.        canonical form as we go.  f is open in text mode.  Canonical
  456.        form uses crlf's as line separators. */
  457.     int count, status = 0;
  458.     byte c, *tb1, *tb2;
  459.     int i, nbytes;
  460.     int nspaces = 0;
  461.     do    /* read and write the whole file... */
  462.     {
  463.         if (longcount < (word32) DISKBUFSIZE)
  464.             count = (int)longcount;
  465.         else
  466.             count = DISKBUFSIZE;
  467.         count = fread(textbuf,1,count,f);
  468.         if (count>0)
  469.         {    /* Convert by adding CR before LF */
  470.             tb1 = textbuf;
  471.             tb2 = textbuf2;
  472.             for (i=0; i<count; ++i)
  473.             {       switch (CONVERSION) {
  474.                 case EXT_CONV:
  475.                     c = EXT_C(*tb1++);
  476.                     break;
  477.                 case INT_CONV:
  478.                     c = INT_C(*tb1++);
  479.                     break;
  480.                 default:
  481.                     c = *tb1++;
  482.                 }
  483.                 if (strip_spaces)
  484.                 {
  485.                     if (c == ' ')    /* Don't output spaces yet */
  486.                         nspaces += 1;
  487.                     else
  488.                     {    if (c == '\n')
  489.                         {    *tb2++ = '\r';
  490.                             nspaces = 0;    /* Delete trailing spaces */
  491.                         }
  492.                         if (nspaces)    /* Put out spaces here */
  493.                         {    do
  494.                                 *tb2++ = ' ';
  495.                             while (--nspaces);
  496.                         }
  497.                         *tb2++ = c;
  498.                     }
  499.                 }
  500.                 else
  501.                 {    if (c == '\n')
  502.                         *tb2++ = '\r';
  503.                     *tb2++ = c;
  504.                 }
  505.             }
  506.             nbytes = tb2 - textbuf2;
  507.             if (fwrite(textbuf2,1,nbytes,g) != nbytes )
  508.             {   /* Problem: return error value */
  509.                 status = -1;
  510.                 break;
  511.             }
  512.             longcount -= count;
  513.         }
  514.         /* if text block was short, exit loop */
  515.     } while (count==DISKBUFSIZE);
  516.     burn(textbuf);    /* burn sensitive data on stack */
  517.     burn(textbuf2);
  518.     return(status);
  519. }    /* copyfile_to_canon */
  520.  
  521.  
  522. int copyfile_from_canon (FILE *f, FILE *g, word32 longcount)
  523. {    /* copy file f to file g, for longcount bytes.  Convert from
  524.        canonical to local form as we go.  g is open in text mode.  Canonical
  525.        form uses crlf's as line separators. */
  526.     int count, status = 0;
  527.     byte c, *tb1, *tb2;
  528.     int i, nbytes;
  529.     do    /* read and write the whole file... */
  530.     {
  531.         if (longcount < (word32) DISKBUFSIZE)
  532.             count = (int)longcount;
  533.         else
  534.             count = DISKBUFSIZE;
  535.         count = fread(textbuf,1,count,f);
  536.         if (count>0)
  537.         {    /* Convert by removing CR's */
  538.             tb1 = textbuf;
  539.             tb2 = textbuf2;
  540.             for (i=0; i<count; ++i)
  541.             {       switch (CONVERSION) {
  542.                 case EXT_CONV:
  543.                     c = EXT_C(*tb1++);
  544.                     break;
  545.                 case INT_CONV:
  546.                     c = INT_C(*tb1++);
  547.                     break;
  548.                 default:
  549.                     c = *tb1++;
  550.                 }
  551.                 if (c != '\r')
  552.                     *tb2++ = c;
  553.             }
  554.             nbytes = tb2 - textbuf2;
  555.             if (fwrite(textbuf2,1,nbytes,g) != nbytes )
  556.             {   /* Problem: return error value */
  557.                 status = -1;
  558.                 break;
  559.             }
  560.             longcount -= count;
  561.         }
  562.         /* if text block was short, exit loop */
  563.     } while (count==DISKBUFSIZE);
  564.     burn(textbuf);    /* burn sensitive data on stack */
  565.     burn(textbuf2);
  566.     return(status);
  567. }    /* copyfile_from_canon */
  568.  
  569.  
  570. int copyfiles_by_name(char *srcFile, char *destFile)
  571. /*    Copy srcFile to destFile  */
  572. {
  573.     FILE *f, *g;
  574.     int status = 0;
  575.     long fileLength;
  576.  
  577.     if (((f=fopen(srcFile,FOPRBIN)) == NULL) ||
  578.         ((g=fopen(destFile,FOPWBIN)) == NULL))
  579.         /* Can't open files */
  580.         return(-1);
  581.  
  582.     /* Get file length and copy it */
  583.     fseek(f,0L,SEEK_END);
  584.     fileLength = ftell(f);
  585.     rewind(f);
  586.     status = copyfile(f,g,fileLength);
  587.     fclose(f);
  588.     if (write_error(g))
  589.         status = -1;
  590.     fclose(g);
  591.     return(status);
  592. }    /* copyfiles_by_name */
  593.  
  594.  
  595. int make_canonical(char *srcFile, char *destFile)
  596. /*    Copy srcFile to destFile, converting to canonical text form  */
  597. {
  598.     FILE *f, *g;
  599.     int status = 0;
  600.     long fileLength;
  601.  
  602.     if (((f=fopen(srcFile,FOPRTXT)) == NULL) ||
  603.         ((g=fopen(destFile,FOPWBIN)) == NULL))
  604.         /* Can't open files */
  605.         return(-1);
  606.  
  607.     /* Get file length and copy it */
  608.     fseek(f,0L,SEEK_END);
  609.     fileLength = ftell(f);
  610.     rewind(f);
  611.     CONVERSION = INT_CONV;
  612.     status = copyfile_to_canon(f,g,fileLength);
  613.     CONVERSION = NO_CONV;
  614.     fclose(f);
  615.     if (write_error(g))
  616.         status = -1;
  617.     fclose(g);
  618.     return(status);
  619. }    /* make_canonical */
  620.  
  621.  
  622. int rename2(char *srcFile, char *destFile)
  623. /*    Like rename() but will try to copy the file if the rename fails.
  624.     This is because under OS's with multiple physical volumes if the
  625.     source and destination are on different volumes the rename will fail */
  626. {
  627.     FILE *f, *g;
  628.     int status = 0;
  629.     long fileLength;
  630.  
  631. #ifdef VMS
  632.     if (rename(srcFile,destFile) != 0)
  633. #else
  634.     if (rename(srcFile,destFile) == -1)
  635. #endif
  636.     {    /* Rename failed, try a copy */
  637.         if (((f=fopen(srcFile,FOPRBIN)) == NULL) ||
  638.             ((g=fopen(destFile,FOPWBIN)) == NULL))
  639.             /* Can't open files */
  640.             return(-1);
  641.  
  642.         /* Get file length and copy it */
  643.         fseek(f,0L,SEEK_END);
  644.         fileLength = ftell(f);
  645.         rewind(f);
  646.         status = copyfile(f,g,fileLength);
  647.         if (write_error(g))
  648.             status = -1;
  649.  
  650.         /* Zap source file if the copy went OK, otherwise zap the (possibly
  651.            incomplete) destination file */
  652.         if (status >= 0)
  653.         {    wipeout(f);        /* Zap source file */
  654.             fclose(f);
  655.             remove(srcFile);
  656.             fclose(g);
  657.         }
  658.         else
  659.         {    if (is_regular_file(destFile))
  660.             {    wipeout(g);        /* Zap destination file */
  661.                 fclose(g);
  662.                 remove(destFile);
  663.             } else
  664.                 fclose(g);
  665.             fclose(f);
  666.         }
  667.     }
  668.     return(status);
  669. }
  670.  
  671.  
  672. int readPhantomInput(char *filename)
  673. /* read the data from stdin to the phantom input file */
  674. {    FILE *outFilePtr;
  675.     byte buffer[ 512 ];
  676.     int bytesRead, status = 0;
  677.  
  678.     if (verbose)
  679.         fprintf(pgpout, "writing stdin to file %s\n", filename);
  680.     if ((outFilePtr = fopen(filename,FOPWBIN)) == NULL)
  681.         return(-1);
  682.  
  683. #if defined(MSDOS) || defined(OS2)
  684.     /* Under DOS must set input stream to binary mode to avoid data mangling */
  685.     setmode(fileno(stdin), O_BINARY);
  686. #endif /* MSDOS || OS2 */
  687.     while ((bytesRead = fread (buffer, 1, 512, stdin)) > 0)
  688.         if (fwrite (buffer, 1, bytesRead, outFilePtr) != bytesRead)
  689.         {    status = -1;
  690.             break;
  691.         }
  692.     if (write_error(outFilePtr))
  693.         status = -1;
  694.     fclose (outFilePtr);
  695. #if defined(MSDOS) || defined(OS2)
  696.     setmode(fileno(stdin), O_TEXT);    /* Reset stream */
  697. #endif /* MSDOS || OS2 */
  698.     return(status);
  699. }
  700.  
  701.  
  702. int writePhantomOutput(char *filename)
  703. /* write the data from the phantom output file to stdout */
  704. {    FILE *outFilePtr;
  705.     byte buffer[ 512 ];
  706.     int bytesRead, status = 0;
  707.  
  708.     if (verbose)
  709.         fprintf(pgpout, "writing file %s to stdout\n", filename);
  710.     /* this can't fail since we just created the file */
  711.     outFilePtr = fopen(filename,FOPRBIN);
  712.  
  713. #if defined(MSDOS) || defined(OS2)
  714.     setmode(fileno(stdout), O_BINARY);
  715. #endif /* MSDOS || OS2 */
  716.     while ((bytesRead = fread (buffer, 1, 512, outFilePtr)) > 0)
  717.         if (fwrite (buffer, 1, bytesRead, stdout) != bytesRead)
  718.         {    status = -1;
  719.             break;
  720.         }
  721.     fclose (outFilePtr);
  722.     fflush(stdout);
  723.     if (ferror(stdout))
  724.     {    status = -1;
  725.         fprintf(pgpout, PSTR("\007Write error on stdout.\n"));
  726.     }
  727. #if defined(MSDOS) || defined(OS2)
  728.     setmode(fileno(stdout), O_TEXT);
  729. #endif /* MSDOS || OS2 */
  730.  
  731.     return(status);
  732. }
  733.  
  734. /* Return the size from the current position of file f to the end */
  735. word32 fsize (FILE *f)
  736. {
  737.     long fpos = ftell (f);
  738.     long fpos2;
  739.  
  740.     fseek (f, 0L, SEEK_END);
  741.     fpos2 = ftell (f);
  742.     fseek (f, fpos, SEEK_SET);
  743.     return (word32)(fpos2 - fpos);
  744. }
  745.  
  746. /* Return TRUE if file filename looks like a pure text file */
  747. int is_text_file (char *filename)
  748. {
  749.     FILE    *f = fopen(filename,"r");    /* FOPRBIN gives problem with VMS */
  750.     int        i, n, bit8 = 0;
  751.     unsigned char buf[512];
  752.     unsigned char *bufptr = buf;
  753.     unsigned char c;
  754.  
  755.     if (!f)
  756.         return(FALSE);    /* error opening it, so not a text file */
  757.     i = n = fread (buf, 1, sizeof(buf), f);
  758.     fclose(f);
  759.     if (n <= 0)
  760.         return(FALSE);    /* empty file or error, not a text file */
  761.     if (compressSignature(buf) >= 0)
  762.         return(FALSE);
  763.     while (i--)
  764.     {    c = *bufptr++;
  765.         if (c & 0x80)
  766.             ++bit8;
  767.         else /* allow BEL BS HT LF VT FF CR EOF control characters */
  768.             if (c < '\007' || (c > '\r' && c < ' ' && c != '\032'))
  769.                 return(FALSE);    /* not a text file */
  770.     }
  771.     if (strcmp(language, "ru") == 0)
  772.         return(TRUE);
  773.     /* assume binary if more than 1/4 bytes have 8th bit set */
  774.     return(bit8 < n / 4);
  775. } /* is_text_file */
  776.  
  777. VOID *xmalloc(unsigned size)
  778. {    VOID *p;
  779.     if (size == 0)
  780.         ++size;
  781.     if ((p = malloc(size)) == NULL)
  782.     {    fprintf(stderr, PSTR("\n\007Out of memory.\n"));
  783.         exitPGP(1);
  784.     }
  785.     return(p);
  786. }
  787.  
  788. /*----------------------------------------------------------------------
  789.  *    temporary file routines
  790.  */
  791.  
  792.  
  793. #define MAXTMPF 8
  794.  
  795. #define    TMP_INUSE    2
  796.  
  797. static struct
  798. {    char path[MAX_PATH];
  799.     int flags;
  800.     int num;
  801. } tmpf[MAXTMPF];
  802.  
  803. static char tmpdir[256];    /* temporary file directory */
  804. static char outdir[256];    /* output directory */
  805. static char tmpbasename[64] = "pgptemp";    /* basename for temporary files */
  806.  
  807.  
  808. /*
  809.  * set directory for temporary files.  path will be stored in
  810.  * tmpdir[] with an appropriate trailing path separator.
  811.  */
  812. void settmpdir(char *path)
  813. {
  814.     char *p;
  815.  
  816.     if (path == NULL || *path == '\0')
  817.     {    tmpdir[0] = '\0';
  818.         return;
  819.     }
  820.     strcpy(tmpdir, path);
  821.     p = tmpdir + strlen(tmpdir)-1;
  822.     if (*p != '/' && *p != '\\' && *p != ']' && *p != ':')
  823.     {    /* append path separator, either / or \ */
  824.         if ((p = strchr(tmpdir, '/')) == NULL &&
  825.             (p = strchr(tmpdir, '\\')) == NULL)
  826.             p = "/";    /* path did not contain / or \, use / */
  827.         strncat(tmpdir, p, 1);
  828.     }
  829. }
  830.  
  831. /*
  832.  * set output directory to avoid a file copy when temp file is renamed to
  833.  * output file.  the argument filename must be a valid path for a file, not
  834.  * a directory.
  835.  */
  836. void setoutdir(char *filename)
  837. {
  838.     char *p;
  839.  
  840.     if (filename == NULL)
  841.     {    strcpy(outdir, tmpdir);
  842.         return;
  843.     }
  844.     strcpy(outdir, filename);
  845.     p = file_tail(outdir);
  846.     strcpy(tmpbasename, p);
  847.     *p = '\0';
  848.     drop_extension(tmpbasename);
  849. #if !defined(BSD42) && !defined(BSD43) && !defined(sun)
  850.     /* we don't depend on pathconf here, if it returns an incorrect value
  851.      * for NAME_MAX (like Linux 0.97 with minix FS) finding a unique name
  852.      * for temp files can fail.
  853.      */
  854.     tmpbasename[10] = '\0';    /* 14 char limit */
  855. #endif
  856. }
  857.  
  858. /*
  859.  * return a unique temporary file name
  860.  */
  861. char *tempfile(int flags)
  862. {
  863.     int i, j;
  864.     int num;
  865.     int fd;
  866. #ifndef UNIX
  867.     FILE *fp;
  868. #endif
  869.  
  870.     for (i = 0; i < MAXTMPF; ++i)
  871.         if (tmpf[i].flags == 0)
  872.             break;
  873.     
  874.     if (i == MAXTMPF)
  875.     {    /* message only for debugging, no need for PSTR */
  876.         fprintf(stderr, "\n\007Out of temporary files\n");
  877.         return(NULL);
  878.     }
  879.  
  880. again:
  881.     num = 0;
  882.     do {
  883.         for (j = 0; j < MAXTMPF; ++j)
  884.             if (tmpf[j].flags && tmpf[j].num == num)
  885.                 break;
  886.         if (j < MAXTMPF)
  887.             continue;    /* sequence number already in use */
  888.         sprintf(tmpf[i].path, "%s%s.%c%02d",
  889.             ((flags & TMP_TMPDIR) && *tmpdir ? tmpdir : outdir),
  890.             tmpbasename, TMP_EXT, num);
  891.         if (!file_exists(tmpf[i].path))
  892.             break;
  893.     }
  894.     while (++num < 100);
  895.  
  896.     if (num == 100)
  897.     {    fprintf(pgpout, "\n\007tempfile: cannot find unique name\n");
  898.         return(NULL);
  899.     }
  900.  
  901. #if defined(UNIX) || defined(VMS)
  902.     if ((fd = open(tmpf[i].path, O_EXCL|O_RDWR|O_CREAT, 0600)) != -1)
  903.         close(fd);
  904. #else
  905.     if ((fp = fopen(tmpf[i].path, "w")) != NULL)
  906.         fclose(fp);
  907.     fd = (fp == NULL ? -1 : 0);
  908. #endif
  909.  
  910.     if (fd == -1)
  911.     {    if (!(flags & TMP_TMPDIR))
  912.         {    flags |= TMP_TMPDIR;
  913.             goto again;
  914.         }
  915. #ifdef UNIX
  916.         else if (tmpdir[0] == '\0')
  917.         {    strcpy(tmpdir, "/tmp/");
  918.             goto again;
  919.         }
  920. #endif
  921.     }
  922.     if (fd == -1)
  923.     {    fprintf(pgpout, PSTR("\n\007Cannot create temporary file '%s'\n"), tmpf[i].path);
  924.         user_error();
  925.     }
  926. #ifdef VMS
  927.     remove(tmpf[i].path);
  928. #endif
  929.  
  930.     tmpf[i].num = num;
  931.     tmpf[i].flags = flags | TMP_INUSE;
  932.     if (verbose)
  933.         fprintf(pgpout, "tempfile: created '%s'\n", tmpf[i].path);
  934.     return(tmpf[i].path);
  935. }    /* tempfile */
  936.  
  937. /*
  938.  * remove temporary file, wipe if necessary.
  939.  */
  940. void rmtemp(char *name)
  941. {
  942.     int i;
  943.  
  944.     for (i = 0; i < MAXTMPF; ++i)
  945.         if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0)
  946.             break;
  947.  
  948.     if (i < MAXTMPF)
  949.     {    if (strlen(name) > 3 && name[strlen(name)-3] == TMP_EXT)
  950.         {    /* only remove file if name hasn't changed */
  951.             if (verbose)
  952.                 fprintf(pgpout, "rmtemp: removing '%s'\n", name);
  953.             if (tmpf[i].flags & TMP_WIPE)
  954.                 wipefile(name);
  955.             if (!remove(name)) {
  956.                 tmpf[i].flags = 0;
  957.             } else if (verbose) {
  958.                 fprintf(stderr,"\nrmtemp: Failed to remove %s",name);                
  959.                 perror ("\nError");
  960.             }
  961.         } else if (verbose)
  962.             fprintf(pgpout, "rmtemp: not removing '%s'\n", name);
  963.     }
  964. }    /* rmtemp */
  965.  
  966. /*
  967.  * make temporary file permanent, returns the new name.
  968.  */
  969. char *savetemp(char *name, char *newname)
  970. {
  971.     int i, overwrite;
  972.     static char buf[MAX_PATH];
  973.  
  974.     if (strcmp(name, newname) == 0)
  975.         return(name);
  976.  
  977.     for (i = 0; i < MAXTMPF; ++i)
  978.         if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0)
  979.             break;
  980.  
  981.     if (i < MAXTMPF)
  982.     {    if (strlen(name) < 4 || name[strlen(name)-3] != TMP_EXT)
  983.         {    if (verbose)
  984.                 fprintf(pgpout, "savetemp: not renaming '%s' to '%s'\n",
  985.                         name, newname);
  986.             return(name);    /* return original file name */
  987.         }
  988.     }
  989.  
  990.     while (file_exists(newname))
  991.     {
  992.         if (batchmode && !force_flag)
  993.         {    fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.\n"),newname);
  994.             return NULL;
  995.         }
  996.         if (is_regular_file(newname))
  997.         {    
  998.             if (force_flag)
  999.             {    /* remove without asking */
  1000.                 remove(newname);
  1001.                 break;
  1002.             }
  1003.             fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.  Overwrite (y/N)? "),
  1004.                 newname);
  1005.             overwrite = getyesno('n');
  1006.         }
  1007.         else
  1008.         {    fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.\n"),newname);
  1009.             if (force_flag)    /* never remove special file */
  1010.                 return NULL;
  1011.             overwrite = FALSE;
  1012.         }
  1013.  
  1014.         if (!overwrite)
  1015.         {    fprintf(pgpout, PSTR("\nEnter new file name: "));
  1016.             getstring(buf, MAX_PATH - 1, TRUE);
  1017.             if (buf[0] == '\0')
  1018.                 return(NULL);
  1019.             newname = buf;
  1020.         }
  1021.         else
  1022.             remove(newname);
  1023.     }
  1024.     if (verbose)
  1025.         fprintf(pgpout, "savetemp: renaming '%s' to '%s'\n", name, newname);
  1026.     if (rename2(name, newname) < 0)
  1027.     {    /* errorLvl = UNKNOWN_FILE_ERROR; */
  1028.         fprintf(pgpout, PSTR("Can't create output file '%s'\n"), newname);
  1029.         return(NULL);
  1030.     }
  1031.     if (i < MAXTMPF)
  1032.         tmpf[i].flags = 0;
  1033.     return(newname);
  1034. }    /* savetemp */
  1035.  
  1036. /*
  1037.  * like savetemp(), only make backup of destname if it exists
  1038.  */
  1039. int savetempbak(char *tmpname, char *destname)
  1040. {
  1041.     char bakpath[MAX_PATH];
  1042. #ifdef UNIX
  1043.     int mode = -1;
  1044. #endif
  1045.  
  1046.     if (is_tempfile(destname))
  1047.         remove(destname);
  1048.     else
  1049.     {    if (file_exists(destname))
  1050.         {
  1051. #ifdef UNIX
  1052.             struct stat st;
  1053.             if (stat(destname, &st) != -1)
  1054.                 mode = st.st_mode & 07777;
  1055. #endif
  1056.             strcpy(bakpath, destname);
  1057.             force_extension(bakpath, BAK_EXTENSION);
  1058.             remove(bakpath);
  1059. #ifdef VMS
  1060.             if (rename(destname, bakpath) != 0)
  1061. #else
  1062.             if (rename(destname, bakpath) == -1)
  1063. #endif
  1064.                 return(-1);
  1065.         }
  1066.     }
  1067.     if (savetemp(tmpname, destname) == NULL)
  1068.         return(-1);
  1069. #ifdef UNIX
  1070.     if (mode != -1)
  1071.         chmod(destname, mode);
  1072. #endif
  1073.     return(0);
  1074. }
  1075.  
  1076. /*
  1077.  * remove all temporary files and wipe them if necessary
  1078.  */
  1079. void cleanup_tmpf(void)
  1080. {
  1081.     int i;
  1082.  
  1083.     for (i = 0; i < MAXTMPF; ++i)
  1084.         if (tmpf[i].flags)
  1085.             rmtemp(tmpf[i].path);
  1086. }    /* cleanup_tmpf */
  1087.